import {
  constructMapParser
} from './BSFormatReader'

const app = getApp()
const fs = wx.getFileSystemManager()
const songDir = wx.env.USER_DATA_PATH + "/songs/";

function unzipPromise(zipFilePath, targetPath) {
  return new Promise((resolve, reject) => {
    fs.unzip({
      zipFilePath: zipFilePath,
      targetPath: targetPath,
      success: (res) => {
        resolve(res); // 解压成功，返回成功结果
      },
      fail: (err) => {
        reject(err); // 解压失败，抛出错误
      }
    });
  });
}

function downloadFilePromise(url, filePath, setProgress = (str) => {}) {
  return new Promise((resolve, reject) => {
    const downLoadTask = wx.downloadFile({
      url: url, // 文件资源的 URL
      filePath: filePath, // 指定文件保存路径
      success: (res) => {
        if (res.statusCode === 200) {
          resolve(res); // 下载成功，返回成功结果
          setProgress("下载成功")
        } else {
          reject(new Error(`Download failed with status code: ${res.statusCode}`));
          setProgress("下载失败:" + res.statusCode) 
        }
      },
      fail: (err) => {
        reject(err); // 下载失败，抛出错误
        setProgress("下载失败:" + err.message) 
      }
    });
    downLoadTask.onProgressUpdate(res=>{
      setProgress("下载中:" + res.progress + "%") 
      // console.log('Progress:', res.progress)
      // console.log('Downloaded:', res.totalBytesWritten)
      // console.log('Total:', res.totalBytesExpectedToWrite)
    })
  });
}

function listFolder(targetPath) {
  fs.readdir({
    dirPath: targetPath,
    success: (res) => {
      const files = res.files
      files.map(file => {
        console.log(`${targetPath}${file}`)
      })
    },
    fail(err) {
      console.log("Error, can't list file", err);
    }
  });
}

function fileExists(filePath) {
  try {
    fs.accessSync(filePath)
    return true;
  } catch (e) {
    return false;
  }
}

function songExist(key) {
  return key in app.globalData.songs && app.globalData.songs[key].parser
}

function deleteDirRecursive(path) {
  const fs = wx.getFileSystemManager();

  fs.readdir({
    dirPath: path,
    success: res => {
      let files = res.files || [];
      let count = 0;

      if (files.length === 0) {
        // 空目录，直接删
        fs.rmdir({
          dirPath: path,
          success: () => console.log(`已删除空目录 ${path}`),
        });
        return;
      }

      files.forEach(file => {
        const fullPath = `${path}/${file}`;
        fs.stat({
          path: fullPath,
          success: statRes => {
            if (statRes.stats.isDirectory()) {
              deleteDirRecursive(fullPath); // 递归删子目录
            } else {
              fs.unlink({
                filePath: fullPath,
                success: () => {
                  count++;
                  if (count === files.length) {
                    // 所有内容删完，删自身
                    fs.rmdir({
                      dirPath: path,
                      success: () => console.log(`已删除目录 ${path}`),
                    });
                  }
                }
              });
            }
          }
        });
      });
    },
    fail: err => {
      console.error('读取目录失败:', err);
    }
  });
}

async function clearTmpFile(){
  const fs = wx.getFileSystemManager();
  
  return fs.readdir({
    dirPath: songDir,
    success: res => {
      res.files.forEach(fileName => {
        const filePath = `${songDir}/${fileName}`;
        const statRes = fs.statSync(filePath)
        if(!statRes.isDirectory()){ // Delete all zip files to save storage.
          fs.unlink({
            filePath,
            success: () => {
              console.log(`已删除文件：${filePath}`);
            },
            fail: err => {
              console.warn(`删除失败：${filePath}`, err);
            }
          });
        } else { // If this is a folder, check if it exists in app.globalData
          const parts = filePath.split('/');
          const key = parts[parts.length - 1]
          if(!(key in app.globalData.songs)){
            deleteDirRecursive(filePath)
          }
        }
      });
    },
    fail: err => {
      console.error('读取临时目录失败:', err);
    }
  });
}

async function downloadSong(item, setProgress = (str) => {}) {
  const key = item.id;

  const targetPath = songDir + key + "/";

  if (!songExist(key)) {
    // 1. Create the folder if not exist
    try {
      fs.accessSync(songDir)
    } catch (e) {
      fs.mkdirSync(songDir, true);
    }

    app.globalData.songs[key] = {"loaded": false}
    await clearTmpFile()

    // 2. Download the zip file
    const url = item.versions[0].downloadURL;
    const targetZip = songDir + key + ".zip"
    const res = await downloadFilePromise(url, targetZip, setProgress)
    console.log("Get zip file for:" + key + ",path:" + targetZip);

    // 3. Unzip the zip file
    setProgress("解压中...")

    try {
      try{
        // 3.0 Delete the folder if exists.
        fs.rmdirSync(targetPath, true)
      }catch(err){
        // Ignore if the folder doesn't
      }

      const unzipRes = await unzipPromise(targetZip, targetPath)
      // 3.1 Encode all files that has strange file names.
      const files = fs.readdirSync(targetPath)
      files.forEach(file => {
        const originalPath = `${targetPath}/${file}`
        const encodedName = encodeURI(file)
        const newPath = `${targetPath}/${encodedName}`
        if (file != encodedName) {
          const renameRes = fs.renameSync(originalPath, newPath)
          console.log("File name changed from:" + originalPath + " to " + newPath + ", result:" + renameRes)
        }
      })
    } catch (err) {
      console.log("Unzip failed", err, typeof targetPath)
    }

    setProgress("解压完成")

    // 4. Parse the info.data file
    const infoPath = targetPath + "info.dat"
    const data = fs.readFileSync(infoPath, 'utf-8')
    setProgress("解析info文件")
    try {
      console.log(data)
      const jsonData = JSON.parse(data)
      const parser = constructMapParser(item, jsonData)

      // 4. Set the path in gloable to avoid load again.
      app.globalData.songs[key] = {
        loaded: true,
        path: targetPath,
        parser: parser
      }
    } catch (e) {
      console.log(e)
      setProgress("解析info文件失败" + e.message)
    }

    setProgress("解析info文件成功")
  }
}

module.exports = {songExist, downloadSong, listFolder}